﻿#ifndef mbObj
#include "sys_ext.h" 
#include "os_obj.h"
#include "mbapp.h"
#include "com_def.h"

mb_obj_type mbObj;
#define mbPORT  USART2
#define mbURT_IRQn                   USART2_IRQn
#endif

static void mbswTimerEnable(void);
static void mb_timer_handler(void);
static void mb_cb_set(void);
static void mbObjInit(mb_mode_type mbMode);
static void mbPortTx1Rx0Enable(uint8_t mode);
static void mb_port_Init(mb_mode_type mbMode, uint32_t ulBaudRate, mb_parity_type eParity);
static void mbDataSend(void);
static void mb_port_hal_cfg(void);

/*****************************************************************************//*!
* @brief UART0 RX interrupt routine.
* @brief   Uart interrupt.
*             
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void mbISR()
{
    volatile uint32_t IntSt;
	volatile uint8_t Data; 
     
	mbObj.timeout_cnt = 0;
    
    IntSt = mbPORT->STATR;
	
    if(IntSt & USART_STATR_RXNE)
    {
        Data = mbPORT->DATAR;
        
        mbObj.run_st.bits.port_st = 1;
   
        if(MB_RX_RCVEND == mbObj.rcv_st)
            return;

        if(mbObj.snd_st != MB_TX_IDLE)
            return;
        
        mbObj.rcv_st = MB_RX_RCV;                                                    //指示正在接收数据
        mbswTimerEnable();
        
        if(mbObj.rcv_cnt >= MB_BUFF_SIZE)
            return;                                                                  //指针越界检查
       
        if((IntSt & (USART_STATR_PE | USART_STATR_FE | USART_STATR_ORE) ) != 0)   //帧错误 //只读，由硬件管理
        {
            if(mbObj.rcv_cnt >= 1)
            {
                mbObj.err_st.bits.hal = 1;
            }
        }
        
	    mbObj.adu_buff[mbObj.rcv_cnt ++] = Data;  
        
    }
	else if( (mbObj.snd_size <= mbObj.snd_cnt) && (IntSt & USART_STATR_TC))
    {
        mbObj.snd_st = MB_TX_IDLE;                                               //发送结束   
        if(mbObj.run_st.bits.master_mode)                                         //主机进入接收等待状态
        {
            mbObj.rcv_st = MB_RX_WAIT;
        }
		mbPortTx1Rx0Enable(0);    
    }
    else if( IntSt & USART_STATR_TXE)
    {
        if(mbObj.snd_size > mbObj.snd_cnt)
        {
            mbPORT->DATAR  =  mbObj.adu_buff[mbObj.snd_cnt++];
        }
		else                                  //写缓冲区结束
		{
            mbPORT->CTLR1 &= ~((uint32_t)(USART_CTLR1_TXEIE));
            mbPORT->CTLR1 |= (uint32_t)(USART_CTLR1_TCIE);
		}    
    }
    else
    {
        
    }
}

/*****************************************************************************//*!
* @brief   	com modle init .
*               
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
static void mb_port_Init(mb_mode_type mbMode, uint32_t ulBaudRate, mb_parity_type eParity) 
{
    USART_InitTypeDef cfg;
    
    mb_port_hal_cfg();
    
    mbObjInit(mbMode);

    cfg.USART_BaudRate = ulBaudRate;
    cfg.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    cfg.USART_HardwareFlowControl = 0;
    
    if (MB_PAR_NONE == eParity) {
        cfg.USART_Parity = USART_Parity_No;
        cfg.USART_StopBits = USART_StopBits_2;
        cfg.USART_WordLength = USART_WordLength_8b;
    } else if (MB_PAR_ODD == eParity) {
        cfg.USART_Parity = USART_Parity_Odd;
        cfg.USART_StopBits = USART_StopBits_1;
        cfg.USART_WordLength = USART_WordLength_9b;
    } else {
        cfg.USART_Parity = USART_Parity_Even;
        cfg.USART_StopBits = USART_StopBits_1;
        cfg.USART_WordLength = USART_WordLength_9b;
    }

    if (ulBaudRate > 19200) {
        mbObj.rtu_timer_sv = 3;
    } else {
		mbObj.rtu_timer_sv = (com_timer_cal(ulBaudRate, (35*11+9)/10, 300, 12000) + 99)/100;
    }
    
    
    USART_Init(mbPORT, &cfg);

    USART_Cmd(mbPORT, ENABLE);
    
    nvic_irq_set(mbURT_IRQn,0x0F,1);

    mbPortTx1Rx0Enable(0);
}

/*****************************************************************************//*!
*
* @brief   Uart En or Dis.
*             
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/

static void mbPortTx1Rx0Enable(uint8_t mode) {
	volatile uint8_t u8Temp;
	
	mbPORT->CTLR1   |= (uint32_t)USART_CTLR1_UE;

	if(0 == mode)
	{
        mbRxEnable();
        
		mbPORT->CTLR1   &= ~((uint32_t)USART_CTLR1_TXEIE | USART_CTLR1_TCIE);
		mbPORT->CTLR1   |= (uint32_t)USART_CTLR1_RE;
		
		u8Temp        = mbPORT->DATAR;
		while((mbPORT->STATR & (USART_STATR_RXNE | USART_STATR_ORE)) != 0)
		{
            u8Temp        = mbPORT->DATAR;
		}
		
		(void) u8Temp;

		mbPORT->CTLR1   |= USART_CTLR1_RXNEIE;
	}
	else
	{
		mbPORT->CTLR1   &= ~((uint32_t)USART_CTLR1_RXNEIE | USART_CTLR1_RE);
		
		mbPORT->CTLR1   |= (uint32_t)USART_CTLR1_TE;
		mbTxEnable();
    	
		//mbPORT->DT     =  mbObj.adu_buff[mbObj.snd_cnt++];
		mbPORT->CTLR1   |= (uint32_t)(USART_CTLR1_TXEIE);
	}
}

/*****************************************************************************//*!
*
* @brief   Send data.
*             
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
static void mbDataSend(void) 
{
    mbPortTx1Rx0Enable(1);
}


/*****************************************************************************//*!
*
* @brief   RTU timer enable.
*             
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
static void mbswTimerEnable(void)
{
    mbObj.rtu_timer_cnt = 0;	
    mbObj.b_rtu_timer_on = 1;
}


/*****************************************************************************//*!
*
* @brief   Timeout handle.
*          called from ext timer 1 ms
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
static void mb_timer_handler(void)
{
   mb_rtu_timer_run(&mbObj);
}

/*****************************************************************************//*!
*
* @brief   mb object init.
*             
* @param   none
*
* @return  TURE
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
static void mbObjInit(mb_mode_type mbMode) {

    mb_obj_init(&mbObj);
    mbObj.adu_send = &mbDataSend;

    mbObj.run_st.bits.rtu_mode = 1;

    mb_cb_set();
    
    mbObj.master.err_cnt = 0;    
    
    //SLAVE FUNCTION INIT
    if (MB_RTU_SLAVE == mbMode) {

    } else {
        //MASER FUNCTION INIT
        mbObj.run_st.bits.master_mode = 1;
    }

    vtask_list_add(&app_tick_task_list, mb_timer_handler);
}
